package com.jiepos.mpos.common.service;

import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MultipartFile;

import com.jiepos.mpos.biz.affix.service.AppAffixInfService;
import com.jiepos.mpos.common.constant.DBConstant;
import com.jiepos.mpos.common.constant.ExceptionConstant;
import com.jiepos.mpos.common.constant.RspCodeConstant;
import com.jiepos.mpos.common.constant.SystemConstant;
import com.jiepos.mpos.common.dao.LogClientKeyDao;
import com.jiepos.mpos.common.entity.App_Affix_InfEntity;
import com.jiepos.mpos.common.entity.GpsEntity;
import com.jiepos.mpos.core.entity.MposResponse;
import com.jiepos.mpos.core.util.DateUtil;
import com.jiepos.mpos.core.util.FileUtils;
import com.jiepos.mpos.core.util.StringUtils;
import com.jiepos.mpos.core.util.Tool3DES;

/**
 * 
 * <p>标题: —— 客户端请求抽象方法</p>
 * <p>模块: 通用平台</p>
 * <p>版权: Copyright (c) 2017 江苏杰博实信息技术有限公司
 * @author 娄伟峰
 * @version 1.0
 * @since 2017年9月13日 下午3:28:55
 * @history（历次修订内容、修订人、修订时间等）
 */
public abstract class AbrBaseHttpService {
	private final Logger log = LoggerFactory.getLogger(AbrBaseHttpService.class);

	/** 子类的日志 */
	protected final Logger subLog = LoggerFactory.getLogger(getClass());

	@Autowired
	private LogClientKeyDao logClientKeyDao;
	@Autowired
	private SystemService systemService;

	@Autowired
	private AppAffixInfService appAffixInfService;

	/**
	 * 获取响应map集合
	 * @param rspCode
	 * @param rspMsg
	 * @param dataMap
	 * @return Map
	 */
	public Map getRspMap(String rspCode,String rspMsg,Map dataMap){
		Map rspMap = new HashMap();
		Map rspCodeMap = this.getRspCodeListMap();
 		rspMap.put(SystemConstant.RSP_CODE, rspCode);
 		if(StringUtils.isBlank(rspMsg)){
 			rspMap.put(SystemConstant.RSP_MSG,rspCodeMap.get(rspCode));	
 		}else{
 			rspMap.put(SystemConstant.RSP_MSG,rspMsg);	
 		}
		if(dataMap != null){
			rspMap.put(SystemConstant.RSP_DATAMAP,dataMap);
		}else{
			rspMap.put(SystemConstant.RSP_DATAMAP,new HashMap());
		}
		
		log.debug("客户端响应消息：{}",rspMap);
		return rspMap;
	}
	
	
	private Map getSignRspMap(String rspCode,String rspMsg,Map dataMap){
		Map rspMap = new HashMap();
		Map rspCodeMap = this.getRspCodeListMap();
 		rspMap.put(SystemConstant.RSP_CODE, rspCode);
 		if(StringUtils.isBlank(rspMsg)){
 			rspMap.put(SystemConstant.RSP_MSG,rspCodeMap.get(rspCode));	
 		}else{
 			rspMap.put(SystemConstant.RSP_MSG,rspMsg);	
 		}
		if(dataMap != null){
			rspMap.put(SystemConstant.RSP_DATAMAP,dataMap);
		}else{
			rspMap.put(SystemConstant.RSP_DATAMAP,new HashMap());
		}
		
		log.debug("签名验证完毕反馈消息：{}",rspMap);
		return rspMap;
	}
	
	/**
	 * 获取缓存中的返回给客户端的代码
	 * @return Map
	 */
	public Map getRspCodeListMap(){
		Map codeListMap = new HashMap();
		List<Map> list = systemService.getCodeListByTp(SystemConstant.REDIS_RSP_CODE_MSG); 
		Map dataMap = new HashMap();
		Map map = null;
		if(list != null && list.size() > 0){
			for(int i = 0 ; i < list.size() ; i++){
				map = (Map)list.get(i);
				String code_val = String.valueOf(map.get("code_val"));
				String code_desc = String.valueOf(map.get("code_desc"));
				dataMap.put(code_val, code_desc);
			}
		}
	
		return dataMap;
	}
	/**
	 * 获取提现响应码类型
	 * @return
	 */
	public Map getCashRspCodeListMap(){
		Map codeListMap = new HashMap();
		List<Map> list = systemService.getCodeListByTp(SystemConstant.REDIS_CASH_CODE_MSG); 
		Map dataMap = new HashMap();
		Map map = null;
		if(list != null && list.size() > 0){
			for(int i = 0 ; i < list.size() ; i++){
				map = (Map)list.get(i);
				String code_val = String.valueOf(map.get("code_val"));
				String code_desc = String.valueOf(map.get("code_desc"));
				dataMap.put(code_val, code_desc);
			}
		}
	
		return dataMap;
	}
	
	
	/**
	 * 匹配客户端秘钥
	 * @param request 请求对象
	 * @param serial_number 流水号
	 * @param sign 客户端上送的签名
	 * @param random_number 客户端上送的随机数
	 * @param version 客户端上送的版本号
	 * @param serviceData 拼装好的业务数据
	 * @param login_id 登陆账号
	 * @param operate_url 操作url
	 * @param interName 接口名称
	 * @return
	 */
	public Map getLogClientKeyEntity(HttpServletRequest request,String serial_number,String sign,String random_number,
			String version,String serviceData,String login_id,String operate_url,GpsEntity gpsEntity,String interName){
		   Enumeration paramNames = request.getParameterNames();
		StringBuilder sb = new StringBuilder();
		while (paramNames.hasMoreElements()) {
		    String paramName = (String) paramNames.nextElement();
		    String[] paramValues = request.getParameterValues(paramName);
		    if (paramValues.length == 1) {
		      	String paramValue = paramValues[0];
		     	if (paramValue.length() != 0) {
	 	   	  		sb.append(paramName+"="+paramValue+"&");
		   	  	}
		    }
	    }
	    log.debug("接口[{}]请求参数：{}",interName,sb.toString());
		if(StringUtils.isBlank(sign) || StringUtils.isBlank(random_number) || StringUtils.isBlank(serial_number)){
			return this.getSignRspMap(RspCodeConstant.RSPCODE_200001, null, null);
		}
	 	sign = sign.toUpperCase();	 	
		random_number = random_number.toUpperCase();
	 
	    String tempServiceData = DateUtil.getCurrDateStr()+serviceData;
		log.debug("接口[{}]签名字符串：[{}]",interName,tempServiceData);
		//先得到加密的明文
		String keyData = StringUtils.MD5(DateUtil.getCurrDateStr()+version);	
		log.debug("接口[{}]keyData：[{}]",interName,keyData);
		//得到加密秘钥
		String key1 = Tool3DES.trides_crypt(SystemConstant.LOC_KEY, keyData);
		log.debug("接口[{}]key1：[{}]",interName,key1);
		//获得加密的随机数		
		String cryptStr = Tool3DES.trides_crypt(key1,random_number );
		log.debug("接口[{}]cryptStr：[{}]",interName,cryptStr);
		String logClientKeySql = "select t.*,ROUND(TO_NUMBER(sysdate - to_date(to_char(rec_upd_ts, 'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss')) * 24 * 60*60) as dif_tm from "+DBConstant.Table.T_APP_LOG_CLIENT_KEY+" t where RANDOM_NUMBER=? ";
		List paramList = new ArrayList();
		paramList.add(cryptStr.toUpperCase());
		List<Map> logClientKeyList = logClientKeyDao.queryForList(logClientKeySql, paramList);
		
		//App_Log_Client_KeyEntity logClientKeyEntity = logClientKeyDao.findByParam("RANDOM_NUMBER", cryptStr.toUpperCase());
		if(logClientKeyList == null || logClientKeyList.size() == 0){
//			 log.debug("接口[{}]获取本地随机数失败,加密随机数：[{}]",interName,cryptStr);
			return this.getSignRspMap(RspCodeConstant.RSPCODE_200099, null, null);
		}else{		 
			Map logClientKeyMap = logClientKeyList.get(0);
			String token_key = String.valueOf(logClientKeyMap.get("token_key"));
			String dif_tm = String.valueOf(logClientKeyMap.get("dif_tm"));
			String temp_random_number = String.valueOf(logClientKeyMap.get("random_number"));
			String rec_st = String.valueOf(logClientKeyMap.get("rec_st"));
			String custom_no = String.valueOf(logClientKeyMap.get("custom_no"));
			
			String tempLogClientKeySql = "select * from (select t.* from "+DBConstant.Table.T_APP_LOG_CLIENT_KEY+" t where custom_no='"+custom_no+"'  order by rec_id desc) where rownum=1";
			 
			List<Map> tempLogClientKeyList = logClientKeyDao.queryForList(tempLogClientKeySql, null);
			if(tempLogClientKeyList != null && tempLogClientKeyList.size() > 0){
				Map tempLogMap = tempLogClientKeyList.get(0);
				String temp_token_key = String.valueOf(tempLogMap.get("token_key"));
				log.debug("接口[{}]temp_token_key：[{}]",interName,temp_token_key);
				if(!token_key.equals(temp_token_key)){
					String updateClientSql = "update "+DBConstant.Table.T_APP_LOG_CLIENT_KEY+" set rec_st='0',rec_upd_usr_id='system'  where random_number='"+temp_random_number+"'";
					logClientKeyDao.update(updateClientSql);
					return this.getSignRspMap(RspCodeConstant.RSPCODE_200099, null, null);
				}
			}
			
			log.debug("接口[{}]dif_tm：[{}]",interName,dif_tm);
			log.debug("接口[{}]token_key：[{}]",interName,token_key);
			if(StringUtils.isBlank(dif_tm)){
				dif_tm = "0";
			}
			//退出接口不进行token超时验证
			if(!"httpcommon/logout.do".equals(operate_url)){
				if(Integer.parseInt(dif_tm) > 1800 ){
					log.debug("接口[{}]token超时了",interName);
					String updateClientSql = "update "+DBConstant.Table.T_APP_LOG_CLIENT_KEY+" set rec_st='0',rec_upd_usr_id='system'  where random_number='"+temp_random_number+"'";
					logClientKeyDao.update(updateClientSql);
					return this.getSignRspMap(RspCodeConstant.RSPCODE_200099, null, null);
				}else{
					String updateClientSql = "update "+DBConstant.Table.T_APP_LOG_CLIENT_KEY+" set rec_upd_ts=SYSTIMESTAMP  where random_number='"+temp_random_number+"'";
					logClientKeyDao.update(updateClientSql);
				}
			}
			//得到客户端加密的秘钥
			String decrypt_key = Tool3DES.trides_decrypt(cryptStr, token_key).toUpperCase();
			log.debug("接口[{}]decrypt_key：[{}]",interName,decrypt_key);
			String MD5Str = StringUtils.MD5(tempServiceData).toUpperCase();
			log.debug("接口[{}]MD5Str：[{}]",interName,MD5Str);
			String local_sign = Tool3DES.trides_crypt(decrypt_key, MD5Str).toUpperCase();
			log.debug("接口[{}]本地签名：[{}]",interName,local_sign);
			log.debug("接口[{}]客户端签名：[{}]",interName,sign);
			if(StringUtils.isBlank(sign)){
				//签名为空
				return this.getSignRspMap(RspCodeConstant.RSPCODE_200002, null, null);
			}else{
				//验证签名是否正确
				if((sign.toUpperCase()).equals(local_sign)){
				//	log.debug("需要验证token是否超时，目前还没做");
					return this.getSignRspMap(SystemConstant.RSPCODE_SUCCESS, null, null);
					
				}else{
					return this.getSignRspMap(RspCodeConstant.RSPCODE_200002, null, null);
				} 
			}

		}  
 
	}
	
	
	/**
	 * 未登录时校验签名
	 * @param serviceData 业务数据
	 * @param sign 签名
	 * @param interName 接口名称
	 * @return
	 */
	public Map checkCommonSign(HttpServletRequest request,String serviceData,String sign,String interName){
 	    Enumeration paramNames = request.getParameterNames();
	    StringBuilder sb = new StringBuilder();
	    while (paramNames.hasMoreElements()) {
		    String paramName = (String) paramNames.nextElement();
		    String[] paramValues = request.getParameterValues(paramName);
		    if (paramValues.length == 1) {
		      	String paramValue = paramValues[0];
		     	if (paramValue.length() != 0) {
	 	   	  		sb.append(paramName+"="+paramValue+"&");
		   	  	}
		    }
	    }
	    log.debug("接口[{}]请求参数：{}",interName,sb.toString());
		log.debug("接口[{}]签名字符串：{}",interName,serviceData);
		String localSign = StringUtils.MD5(serviceData);		
		log.debug("接口[{}]本地签名：{}",interName,localSign);
		log.debug("接口[{}]客户端签名：{}",interName,sign);
		if(!StringUtils.isBlank(localSign) && !StringUtils.isBlank(sign)&& localSign.toUpperCase().equals(sign.toUpperCase()) && !StringUtils.isBlank(sign)){
			return this.getSignRspMap(SystemConstant.RSPCODE_SUCCESS, SystemConstant.RSPCODE_SUCCESS_MSG, null);
		}else{
			return this.getSignRspMap(RspCodeConstant.RSPCODE_200002, null, null);
		}
	}

	//-------- 短信验证码生成策略----

	/** 纯数字验证码 */
	private static String NUMBER = "1234567890";

	/** 数字字母验证码(字符'o'不易识别，已剔除) */
	private static String NUMBERANTCHAR = "1234567890abcdefghijkmnpqrstuvwxyz";

	/**
	 * 创建指定数量的随机字符串
	 * @param numberFlag 是否是数字
	 * @param length 长度
	 * @return
	 */
	protected String createRandom(boolean numberFlag, int length){
		String retStr = "";
		String strTable = numberFlag ? NUMBER : NUMBERANTCHAR;
		int len = strTable.length();
		boolean bDone = true;
		do {
			retStr = "";
			int count = 0;
			for (int i = 0; i < length; i++) {
				double dblR = Math.random() * len;
				int intR = (int) Math.floor(dblR);
				char c = strTable.charAt(intR);
				if (('0' <= c) && (c <= '9')) {
					count++;
				}
				retStr += strTable.charAt(intR);
			}
			if (count >= 2) {
				bDone = false;
			}
		} while (bDone);
		return retStr;
	}

	//app 上传图片接口
	protected MposResponse uploadImgForApp(HttpServletRequest request, HttpServletResponse response, MultipartFile file,String custom_uuid,String affix_tp,String store_tp,String custom_name,String custom_no){
		MposResponse resp = new MposResponse();
		try {
			//尝试从数据库加载已有附件信息对象
			App_Affix_InfEntity entity = appAffixInfService.getAffixInfByParam(custom_uuid, affix_tp, store_tp);
			if(entity == null){
				//新增图片 文件不能为空
				if(file == null){
					return new MposResponse(ExceptionConstant.ERROR);
				}
                //说明还未保存该会员该类型的图片附件信息
                //那么初始化该对象
                entity = new App_Affix_InfEntity();
            }else{
				//修改图片 文件为空的话 直接返回
				if(file == null){
					return resp;
				}
			}
            //查询该会员的图片上传路径（一个会员只有一个路径，第一次上传图片根据系统时间生成路径；后续上传图片全部到第一次的路径）
			String path = appAffixInfService.getUploadFilePath(custom_uuid);

			/*根据业务类型生成图片保存的路径*/
			String filePath = path == null ? getFilePath("app",custom_no) : path;
			String uploadPath = request.getServletContext().getRealPath("/") + filePath;
			/*重命名 保存文件*/
			String uploadName = System.currentTimeMillis()+"_"+custom_no+"_"+store_tp +".jpg";
			File _file = FileUtils.uploadFile(file, uploadPath, uploadName);
			if(_file != null){
                /*设置图片路径，保存至附件表*/
                entity.setAffix_path(filePath + "/" + uploadName);
				entity.setAffix_idx(custom_uuid); //附件索引UUID(会员uuid)
				entity.setAffix_tp(affix_tp);
				entity.setStore_tp(store_tp);
				Map<String,Object> map = new HashMap<>();
				map.put(SystemConstant.SESSION_LOGIN_USER,custom_name);
				String uuid = appAffixInfService.saveAffixPicForApp(entity, map);
				//成功的话 返回uuid
				resp.setRespData(uuid);
            }else{
				resp = new MposResponse(ExceptionConstant.ERROR);
			}
		} catch (Exception e) {
			e.printStackTrace();
			resp = new MposResponse(ExceptionConstant.ERROR);
		}
		return resp;
	}

	/**
	 * 获取上传路径
	 * @param uploadType
	 * @return
	 */
	private String getFilePath(String uploadType,String custom_no){
		StringBuffer path = new StringBuffer("/");
		path.append(SystemConstant.FILE_UPLOAD_PATH);
		if(!StringUtils.isBlank(uploadType)){
			path.append("/").append(uploadType);
		}
		//拼接系统时间
		path.append("/").append(DateUtil.getCurrDateStr());
		//拼接会员编号
		path.append("/").append(custom_no);
		return path.toString();
	}

	/**
	 * 隐藏数据（1身份证号，2手机号）
	 * @param type 1： 身份证号 2：手机号 3:卡号
	 * @param data 要隐藏信息的数据
	 * @return
	 */
	protected String hideData(String type,String data){
		if("1".equals(type)){
			//身份证号
			if(data == null || data.length() != 18){
				return data;
			}
			return data.replaceAll("(\\d{6})\\d{8}(\\d{4})","$1********$2");
		}else if("2".equals(type)){
			//手机号
			if(data == null || data.length() != 11){
				return data;
			}
			return data.replaceAll("(\\d{3})\\d{4}(\\d{4})","$1****$2");
		}else if("3".equals(type)){
			//卡号
			if(data == null || data.length() < 10){
				return data;
			}
			int center = data.length() - 10;
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < center; i++) {
				sb.append("*");
			}
			return data.replaceAll("(\\d{6})\\d{"+center+"}(\\d{4})","$1"+sb.toString()+"$2");
		}else{
			return data;
		}
	}
}
